import { RTPPacket } from "./RTPPacket";
import { findBuffer } from "../utils/Utils";
import { EventEmitter } from "events";

export interface PSPacket {
    payloadType: number;
    timestamp: number;
    ssrc: number;
    isIDE: Boolean;
    streamType?: number;
    payload: Buffer;
}

export const PSPacketDefault: PSPacket = {
    payloadType: -1,
    timestamp: -1,
    ssrc: 0,
    isIDE: false,
    streamType: undefined,
    payload: Buffer.alloc(0),
}

const PSStartCode = Buffer.from([0x00, 0x00, 0x01, 0xBA]);
const PSSysStartCode = Buffer.from([0x00, 0x00, 0x01, 0xBB]);
const PSMStartCode = Buffer.from([0x00, 0x00, 0x01, 0xBC]);
const PESVStartCode = Buffer.from([0x00, 0x00, 0x01, 0xE0]);
const PESAStartCode = Buffer.from([0x00, 0x00, 0x01, 0xC0]);

export class RtpPsTransport extends EventEmitter {
    private rtpPackets: RTPPacket[] = [];
    constructor() {
        super();
    }
    public onData(packet: RTPPacket): void {
        this.processRtpPsPacket(packet);
    }
    private processRtpPsPacket(packet: RTPPacket) {
        this.rtpPackets.push(packet);
        if (packet.marker == 1) {
            // console.log("------------------------------------------------------------------");
            this.processRtpPsFrame(this.rtpPackets);
            // console.log("------------------------------------------------------------------");
            this.rtpPackets = [];
        }
    }
    private parsePSMVideoStreamType(buffer: Buffer) {
        // console.log(`${buffer.toString('hex')}`);
        let streamType = -1;
        let pos = 4;
        const program_stream_map_length = buffer.readUInt16BE(pos);
        pos = pos + 4;
        if (program_stream_map_length + 6 !== buffer.byteLength) {
            return streamType;
        }
        const program_stream_info_length = buffer.readUInt16BE(pos);
        pos = pos + 2 + program_stream_info_length;
        const elementary_stream_map_length = buffer.readUInt16BE(pos);
        pos = pos + 2;
        const mapBuffer = buffer.slice(pos, pos + elementary_stream_map_length);

        pos = 0;
        while (pos <= elementary_stream_map_length - 4) {
            const stream_type = mapBuffer[pos];
            const elementary_stream_id = mapBuffer[pos + 1];
            const elementary_stream_info_length = buffer.readUInt16BE(pos + 2);
            pos = pos + 4 + elementary_stream_info_length;
            if (elementary_stream_id == 0xE0) {
                streamType = stream_type;
                break;
            }
        }
        return streamType;

    }
    private processRtpPsFrame(rtpPackets: RTPPacket[]) {
        if (rtpPackets.length < 2) return;
        let packet: PSPacket = { ...PSPacketDefault, ...{ payloadType: rtpPackets[0].payloadType, timestamp: rtpPackets[0].timestamp, ssrc: rtpPackets[0].ssrc } };
        const nals: Buffer[] = [];
        if (rtpPackets[0].payload.byteLength < 4) return;
        const startCode = rtpPackets[0].payload.slice(0, 4);
        // console.log(`startCode: ${rtpPackets[0].payload.toString('hex')}`);
        if (startCode.readUInt32BE(0) == PSStartCode.readUInt32BE(0)) {
            let psSysPos = findBuffer(rtpPackets[0].payload, PSSysStartCode);
            let psmPos = findBuffer(rtpPackets[0].payload, PSMStartCode);
            // console.log(`psSysPos = ${psSysPos},psmPos = ${psmPos}`);
            if (psSysPos !== -1 && psmPos !== -1) {
                packet.isIDE = true;
                const psmLenght = rtpPackets[0].payload.readUInt16BE(psmPos + 4);
                // console.log(`psmLenght = ${psmLenght}`);
                const psmBuffer = rtpPackets[0].payload.slice(psmPos, psmPos + 6 + psmLenght);
                packet.streamType = this.parsePSMVideoStreamType(psmBuffer);
            } else {
                packet.isIDE = false;
            }
        } else if (startCode.readUInt32BE(0) == PESVStartCode.readUInt32BE(0)) {
            // console.log("#### PESV");
            return;
        } else if (startCode.readUInt32BE(0) == PESAStartCode.readUInt32BE(0)) {
            // console.log("#### PESA");
            return;
        }
        for (let index = 1; index < rtpPackets.length; index++) {
            if (rtpPackets[index].payload.byteLength < 4) continue;
            const rtpStartCode = rtpPackets[index].payload.slice(0, 4);
            if (rtpStartCode.readUInt32BE(0) == PESVStartCode.readUInt32BE(0)) {
                // console.log("@@@@ PESV");
                continue;
            } else if (rtpStartCode.readUInt32BE(0) == PESAStartCode.readUInt32BE(0)) {
                // console.log("@@@@ PESA");
                continue;
            }
            // console.log(`${rtpPackets[index].payload.slice(0, 100).toString('hex')}`);
            nals.push(rtpPackets[index].payload);
        }
        packet.payload = Buffer.alloc(0);
        for (let x = 0; x < nals.length; x++) {
            packet.payload = Buffer.concat([packet.payload, nals[x]]);
        }
        // console.log((packet.payload.slice(0, 100)).toString('hex'));
        this.emit("packet", packet)
        return;
    }
}